#include "common.h"

class ThreadCache
{
public:
    static ThreadCache& getInstance()
    {
        static thread_local ThreadCache tc;
        return tc;
    }

    void* allocate(size_t size)
    {
        if (size == 0)
        {
            size = ALIGNMENT;
        }
        if (size > MAX_BYTES)
        {
            return malloc(size);
        }
        
        size_t index = SizeClass::getIndex(size);
        freeListSize[index]--;
        void* ptr = nullptr;
        if (ptr = freeList[index])
        {
            // 头删
            freeList[index] = *reinterpret_cast<void**>(ptr);
            return ptr;
        }
        // 从中心缓存获取内存
        return fetchFromCentralCache(index);
    }

    void deallocate(void* ptr, size_t size)
    {
        if (!ptr)
        {
            return;
        }
        if (size > MAX_BYTES)
        {
            free(ptr);
            return;
        }

        size_t index = SizeClass::getIndex(size);
        // 头插
        *reinterpret_cast<void**>(ptr) = freeList[index];
        freeList[index] = ptr;
        freeListSize[index]++;

        if (shouldReturn(index))
        {
            returnToCentralCache(freeList[index], size);
        }
    }

    void* fetchFromCentralCache(size_t index)
    {
        void* start = CentralCache::getInstance().fetchRange(index);
        if (!start)
        {
            return nullptr;
        }
        void* result = start;
        freeList[index] = *reinterpret_cast<void**>(start);
        void* cur = start;
        size_t num = 0;
        // 计算内存块的个数
        while (cur != nullptr)
        {
            num++;
            cur = *reinterpret_cast<void**>(cur);
        }
        freeListSize[index] += num;
        return result;
    }

    bool shouldReturn(size_t index)
    {
        size_t threshold = 64;
        return freeListSize[index] > 64;
    }

    void returnToCentralCache(void* start, size_t size)
    {
        size_t index = SizeClass::getIndex(size);
        // 块的实际大小
        size_t batchSize = SizeClass::roundUp(size);
        // 应该归还的数量
        size_t num = freeListSize[index];
        // 如果只有一个，则不归还
        if (num <= 1)
        {
            return;
        }
        // 保留1/4
        size_t keepNum = std::max(num / 4, size_t(1));
        size_t returnNum = num - keepNum;
        void* splitNode = static_cast<void*>((static_cast<char*>(start) + (keepNum - 1) * batchSize));
        void* nextNode = static_cast<void*>((static_cast<char*>(splitNode) + batchSize));
        // 解开两个链表
        *reinterpret_cast<void**>(splitNode) = nullptr;
        // 更新自由链表
        freeList[index] = start;
        freeListSize[index] -= returnNum;
        // 归还内存到中心缓存
        if (returnNum > 0 && nextNode)
        {
            CentralCache::getInstance().returnRange(nextNode, returnNum * batchSize, index);
        }
    }
private:
    ThreadCache()
    {
        freeList.fill(nullptr);
        freeListSize.fill(0);
    }
private:
    std::array<void*, MAX_FREE_LIST_SIZE> freeList;
    std::array<size_t, MAX_FREE_LIST_SIZE> freeListSize;
};